/*
  ==============================================================================

    This file contains the basic framework code for a JUCE plugin processor.

  ==============================================================================
*/

#pragma once

#include "../Modules/RNNFxClone/GRU.h"
#include "../Modules/RNNFxClone/rnnNetWeights.h"
#include "ToneStack.h"
#include "WaveShaperParametric.h"
#include <JuceHeader.h>

#define GAIN_ID "gain"
#define GAIN_NAME "GAIN"
#define PRESENCE_ID "presence"
#define PRESENCE_NAME "PRESENCE"
#define BASS_ID "bass"
#define BASS_NAME "BASS"
#define MID_ID "mid"
#define MID_NAME "MID"
#define TREBLE_ID "treble"
#define TREBLE_NAME "TREBLE"
#define MASTER_ID "master"
#define MASTER_NAME "MASTER"
#define INPUT_ID "input"
#define INPUT_NAME "INPUT"
#define OUTPUT_ID "output"
#define OUTPUT_NAME "OUTPUT"
#define CUSTOM_PARAM_ID "custom"
#define IR_ID "ir"
#define BOOST_ID "boost"
#define CHANNEL_ID "channel"
#define IR_BYPASS_ID "ir_bypass"

typedef enum {
    highpass,
    clipper,
    lowpass,
} BOOST_PROC_ORDER;

typedef enum {
    CH1_input_highpass,
    V1B,
    V1B_highpass,
    V1B_highpass2,
    V1A,
    V1A_highpass,
    V2B,
    V2B_lowpass,
    V2B_highpass,
    V2A,
    V2A_highpass,
    V3B,
    V3B_highpass,
    V3A,
    V3A_highpass,
} CHAN1_PROC_ORDER;

typedef enum {
    CH2_input_highpass,
    V1,
    V1_highpass,
    V2_highpass,
    V2,
    V2_highpass2,
    V2_lowpass,
} CHAN2_PROC_ORDER;

typedef enum {
    tone_stack,
    post_highpass,
    post_lowpass,
    cab,
} POST_GAIN_PROC_ORDER;

//==============================================================================
/**
 */
class Dist_ampAudioProcessor : public juce::AudioProcessor {
public:
    juce::AudioProcessorValueTreeState treeState;
    juce::ValueTree customVariables;

    //==============================================================================
    Dist_ampAudioProcessor();
    ~Dist_ampAudioProcessor() override;

    //==============================================================================
    void prepareToPlay(double sampleRate, int samplesPerBlock) override;
    void releaseResources() override;

#ifndef JucePlugin_PreferredChannelConfigurations
    bool isBusesLayoutSupported(const BusesLayout& layouts) const override;
#endif

    void processBlock(juce::AudioBuffer<float>&, juce::MidiBuffer&) override;

    //==============================================================================
    juce::AudioProcessorEditor* createEditor() override;
    bool hasEditor() const override;

    //==============================================================================
    const juce::String getName() const override;

    bool acceptsMidi() const override;
    bool producesMidi() const override;
    bool isMidiEffect() const override;
    double getTailLengthSeconds() const override;

    //==============================================================================
    int getNumPrograms() override;
    int getCurrentProgram() override;
    void setCurrentProgram(int index) override;
    const juce::String getProgramName(int index) override;
    void changeProgramName(int index, const juce::String& newName) override;

    //==============================================================================
    void getStateInformation(juce::MemoryBlock& destData) override;
    void setStateInformation(const void* data, int sizeInBytes) override;

    void updataParams();

    void setGainValue(float value);
    void setToneStack(float b, float m, float t, float p);
    void enableBoost(bool enable);
    void setIrFile(const juce::File& irFile);
    void bypassIR(const bool bypass);
    float getRMSValue(bool isInput);
    float getPeakValue(bool isInput);
    void setLevel(bool isInput, float value);
    void setChannel(int ch);

private:
    //==============================================================================
    using TubeStage = juce::dsp::WaveShaperParametric<float>;
    using CabSim = juce::dsp::Convolution;
    using WaveShaperStatic = juce::dsp::WaveShaper<float>;
    using IirFilter = juce::dsp::IIR::Filter<float>;
    using ToneStack = juce::dsp::ToneStack<float>;

    juce::dsp::ProcessSpec spec;
    juce::dsp::ProcessorChain<IirFilter, WaveShaperStatic, IirFilter> boostChain;
    juce::dsp::ProcessorChain<IirFilter, // Coupling
        TubeStage, IirFilter, IirFilter, // V1B
        TubeStage, IirFilter, // V1A
        TubeStage, IirFilter, IirFilter, // V2B
        TubeStage, IirFilter, // V2A
        TubeStage, IirFilter, // V3B
        TubeStage, IirFilter // V3A
        >
        chan1Chain;
    juce::dsp::ProcessorChain<IirFilter, // Coupling
        TubeStage, IirFilter, // V1
        IirFilter, TubeStage, IirFilter, IirFilter // V2
        >
        chan2Chain;
    std::unique_ptr<GRU> gru;
    juce::dsp::ProcessorChain<ToneStack, IirFilter, IirFilter, CabSim>
        postGainChain;
    float gainValue, lastGainValue;
    float presenceValue, lastPresenceValue;
    float bassValue, lastBassValue;
    float midValue, lastMidValue;
    float trebleValue, lastTrembelValue;
    float masterValue, lastMasterValue;
    float inputLevel, outputLevel;
    float lastInputLevel, lastOutputLevel;
    float inputGain, outputGain;
    juce::String irFileName, lastIrFileName;
    bool irBypassed, lastIrBypassState;
    float inputRMS = 0.f, outputRMS = 0.f;
    float inputPeak = 0.f, outputPeak = 0.f;
    bool boostEnabled, lastBoostEnabledState;
    int channel, lastChannelValue;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Dist_ampAudioProcessor)
};
